﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#ifndef _UXS_OS_TYPES_H
#define _UXS_OS_TYPES_H

#pragma once

#include "../../../stl_core/ux_stl_core.h"

namespace UX_STL
{
namespace UXTypesExt
{
	using namespace UXTypes;

	
	namespace e_gpu_model
	{
		enum	type	: uint8
		{
			UNKNOWN	= 0x00,
			AMD		= 0x01,
			ATI		= AMD,
			NVIDIA	= 0x02,
			INTEL	= 0x03,
			// TODO: mobile GPU's
		};
	}
	//UX_ENUM_META_OBJECT( e_gpu_model::type );
	


	namespace e_wnd_event
	{
		enum	type :	uint16
		{
			UNKNOWN		= 0,
			KEY			= 1 << 0,
			MOUSE_KEY	= 1 << 1,
			MOUSE		= 1 << 2,
			MESSAGE		= 1 << 3,
			USER		= 1 << 4,
		};

		UX_ENUM_BIT_OPERATIONS( type )
	}
	//UX_ENUM_META_OBJECT( e_wnd_event::type );
	

	namespace e_wnd_style
	{
		enum	type :	uint8
		{
			UNKNOWN					= 0,

			// Window flags
			ALLOW_SIZING			= 0x01,
			TOPMOST					= 0x02,		// disable ALLOW_SIZING
			CENTERED				= 0x04,
			NO_BORDER				= 0x08,		// disable ALLOW_SIZING

			TOOL					= 0x10,		// for hide window only
		
			DEF_WINDOWED			= ALLOW_SIZING | CENTERED,
			DEF_FULLSCREEN			= TOPMOST
		};

		UX_ENUM_BIT_OPERATIONS( type )
	}
	//UX_ENUM_META_OBJECT( e_wnd_style::type );
	

	struct e_date
	{
		enum	type :	uint8
		{
			TIME			= 0x01,				// h:m:s
			MSEC			= 0x02,				// ms
			DATE			= 0x04,				// d/m/y
			TIME_MSEC		= TIME | MSEC,		// h:m:s.ms
			TIME_DATE		= TIME | DATE,		// h:m:s	 d/m/y
			TIME_MSEC_DATE	= TIME_MSEC | DATE,	// h:m:s.ms  d/m/y
		};
	};



	namespace e_glinit_flags
	{
		enum	type :	uint16
		{
			// flags
			DOUBLE_BUFFER			= 0x0200,
			STEREO					= 0x0400,
			
			EXTENDED_CONTEXT		= 0x0100,

			// for EXTENDED_CONTEXT only
			CORE_PROFILE			= 0x1000,	// else use compatibility profile
			ES2_PROFILE				= 0x2000,
			DEBUG_MODE				= 0x4000,
			FORWARD_COMPATIBLE		= 0x8000,
			_CONTEXT_FLAGS_MASK		= 0xF000,
			OPENGL_3_2				= 0x0032,
			OPENGL_3_3				= 0x0033,
			OPENGL_4_0				= 0x0040,
			OPENGL_4_1				= 0x0041,
			OPENGL_4_2				= 0x0042,
			OPENGL_4_3				= 0x0043,
			OPENGL_LAST_VERSION		= 0x00FF,
			_VER_MINOR_MASK			= 0x000F,
			_VER_MINOR_OFFSET		= 0,
			_VER_MAJOR_MASK			= 0x00F0,
			_VER_MAJOR_OFFSET		= 4,

			DEFAULT					= DOUBLE_BUFFER,
			DEFAULT_COMPATIBILITY	= OPENGL_LAST_VERSION | EXTENDED_CONTEXT | FORWARD_COMPATIBLE | DOUBLE_BUFFER,
			DEFAULT_CORE			= OPENGL_LAST_VERSION | EXTENDED_CONTEXT | CORE_PROFILE | FORWARD_COMPATIBLE | DOUBLE_BUFFER,
			DEFAULT_CORE_DEBUG		= DEFAULT_CORE | DEBUG_MODE,
		};
		UX_ENUM_BIT_OPERATIONS( type )
	}



	//
	// System Info
	//

	struct TSystemInfo
	{
		struct TVideoCard
		{
			string				sName;
			uint				uVRAM;		// Mb
			e_gpu_model::type	eGPUModel;
			///
			TVideoCard(): uVRAM(0), eGPUModel(e_gpu_model::UNKNOWN) {}
		};

		struct TProcessor
		{
			string				sName;
			uint				uFreq;		// MHz
			uint8				uNumCores;
			///
			TProcessor(): uFreq(0), uNumCores(0) {}
		};

		array< TVideoCard >		aGPUs;
		array< TProcessor >		aCPUs;
		string					sOSName;
		uint					uRAM,			// Mb
								uVirtualMemory;	// Mb
		bool					bIs64bit;		// 32 or 64 bit OS
		///
		TSystemInfo(): uRAM(0), uVirtualMemory(0), bIs64bit(false) {}
	};


	//
	// Screen Mode
	//

	struct TScreenMode
	{
		UXMath::uvec2	vResolution;
		uint			uColors,
						uFrequency;
		///
		TScreenMode(const UXMath::uvec2 &res, uint colors, uint freq):
			vResolution(res), uColors(colors), uFrequency(freq) {}

		bool operator == (const TScreenMode &right)
		{
			return( All( vResolution == right.vResolution ) and
					uColors == right.uColors and uFrequency  == right.uFrequency );
		}

		bool operator != (const TScreenMode &right)
		{
			return not ( *this == right );
		}
	};



	//
	// API Errors Checker
	//
	
	struct UX_EXPORT TAPIErrorChecker
	{
		// max cicles count while clear errors
		static uint	_GetMaxErrors() { return 10; }


		// OpenGL //
#	ifdef _UXS_USE_OPENGL
		static void ClearGLErrors();
		static bool CheckGLError(uni_c_string pGLFunc, uni_c_string pFunc, uni_c_string pFile, uint uLine);
		static bool CheckGLErrors(uni_c_string pFile, uint uLine);
#	endif

		// OpenGLES //
#	if defined(_UXS_USE_OPENGLES) and !defined(_UXS_USE_OPENGL)
		static void ClearGLErrors();
		static bool CheckGLError(uni_c_string pGLFunc, uni_c_string pFunc, uni_c_string pFile, uint uLine);
		static bool CheckGLErrors(uni_c_string pFile, uint uLine);
#	endif


		// OpenCL //
#	ifdef _UXS_USE_OPENCL
		static bool CheckCLError(int /*cl_int*/ err, uni_c_string pCLFunc, uni_c_string pFunc, uni_c_string pFile, uint uLine);
#	endif


		// OpenAL //
#	ifdef _UXS_USE_OPENAL
		static void ClearALErrors();
		static void ClearALCErrors();
		static bool CheckALError(uni_c_string pALFunc, uni_c_string pFunc, uni_c_string pFile, uint uLine);
		static bool CheckALCError(uni_c_string pALCFunc, uni_c_string pFunc, uni_c_string pFile, uint uLine);
		static bool CheckALErrors(uni_c_string pFile, uint uLine);
		static bool CheckALCErrors(uni_c_string pFile, uint uLine);
#	endif


		// OS //
		static void ClearOSErrors();
		static bool CheckOSError(uni_c_string pOSFunc, uni_c_string pFunc, uni_c_string pFile, uint uLine);
		static bool CheckOSErrors(uni_c_string pFile, uint uLine);
	};

}	// UXTypesExt
}	// UX_STL




//-------------------------- API Errors ---------------------------//

#define __CL_RET_ERROR_VALUE					i_cl_err	// всегда объявлять так переменные хранящие код ошибки
#define VAR_CL_ERROR_RET						cl_int	__CL_RET_ERROR_VALUE = 0
#define __OS_RET_ERROR_VALUE					os_err		// всегда объявлять так переменные...



// Check Error
#ifdef __UX_DEBUG__
#	define __CHECK_API_ERROR( _api, _func )		TAPIErrorChecker::Check##_api##Error( _func, UX_FUNCTION_NAME, __FILE__, __LINE__ )
#	define __CHECK_CL_ERROR( _func )			TAPIErrorChecker::CheckCLError( __CL_RET_ERROR_VALUE, _func, UX_FUNCTION_NAME, __FILE__, __LINE__ )
#else
#	define __CHECK_API_ERROR( _api, _func )		bool(true)
#	define __CHECK_CL_ERROR( _func )			bool(true)
#endif	// __UX_DEBUG__
	

// Clear Errors Stack
#ifdef __UX_DEBUG__
#	define OPENGL_CLEAR_ERRORS()				TAPIErrorChecker::ClearGLErrors()
#	define OPENAL_CLEAR_AL_ERRORS()				TAPIErrorChecker::ClearALErrors()
#	define OPENAL_CLEAR_ALC_ERRORS()			TAPIErrorChecker::ClearALCErrors()
#	define OPENAL_CLEAR_ERRORS()				TAPIErrorChecker::ClearALErrors(); TAPIErrorChecker::ClearALCErrors()
#	define OS_CLEAR_ERRORS()					TAPIErrorChecker::ClearOSErrors()
#else
#	define OPENGL_CLEAR_ERRORS()
#	define OPENGLES_CLEAR_ERRORS()
#	define OPENAL_CLEAR_AL_ERRORS()
#	define OPENAL_CLEAR_ALC_ERRORS()
#	define OPENAL_CLEAR_ERRORS()
#	define OS_CLEAR_ERRORS()
#endif	// __UX_DEBUG__


// Check Errors
#ifdef __UX_DEBUG__
#	define OPENGL_CHECK_ERRORS()				TAPIErrorChecker::CheckGLErrors(  __FILE__, __LINE__ )
#	define OPENAL_CHECK_AL_ERRORS()				TAPIErrorChecker::CheckALErrors(  __FILE__, __LINE__ )
#	define OPENAL_CHECK_ALC_ERRORS()			TAPIErrorChecker::CheckALCErrors( __FILE__, __LINE__ )
#	define OPENAL_CHECK_ERRORS()				(OPENAL_CHECK_AL_ERRORS() | OPENAL_CHECK_ALC_ERRORS())
#	define OSAPI_CHECK_ERRORS()					TAPIErrorChecker::CheckOSErrors(  __FILE__, __LINE__ )
#else
#	define OPENGL_CHECK_ERRORS()				bool(true)
#	define OPENGLES_CHECK_ERRORS()				bool(true)
#	define OPENAL_CHECK_AL_ERRORS()				bool(true)
#	define OPENAL_CHECK_ALC_ERRORS()			bool(true)
#	define OPENAL_CHECK_ERRORS()				bool(true)
#	define OSAPI_CHECK_ERRORS()					bool(true)
#endif	// __UX_DEBUG__



// проверяет не было ли ошибки
// и, если была, то записывает в лог
#define AL_CALL(  _func )						{ _func;  __CHECK_API_ERROR( AL,  #_func );	}
#define ALC_CALL( _func )						{ _func;  __CHECK_API_ERROR( ALC, #_func );	}
#define CL_CALL(  _func )						{ _func;  __CHECK_CL_ERROR( #_func ); }
#define GL_CALL(  _func )						{ _func;  __CHECK_API_ERROR( GL,  #_func );	}
#define OS_CALL(  _func )						{ _func;  if ( !__OS_RET_ERROR_VALUE ) __CHECK_API_ERROR( OS,  #_func ); }


// аналогично предыдущему, но еще записывает
// результат в _res, true - ошибок нет, false - ошибка
#define AL_CALL_B(  _func, _res )				{ _func;  _res = __CHECK_API_ERROR( AL,  #_func ); }
#define ALC_CALL_B( _func, _res )				{ _func;  _res = __CHECK_API_ERROR( ALC, #_func ); }
#define CL_CALL_B(  _func, _res )				{ _func;  _res = __CHECK_CL_ERROR( #_func ); }
#define GL_CALL_B(  _func, _res )				{ _func;  _res = __CHECK_API_ERROR( GL,  #_func ); }
#define OS_CALL_B(  _func, _res )				{ _func;  if ( !__OS_RET_ERROR_VALUE ) _res = __CHECK_API_ERROR( OS,  #_func ); }

#define AL_CALL_BA(  _func, _res )				{ _func;  _res &= __CHECK_API_ERROR( AL,  #_func ); }
#define ALC_CALL_BA( _func, _res )				{ _func;  _res &= __CHECK_API_ERROR( ALC, #_func ); }
#define CL_CALL_BA(  _func, _res )				{ _func;  _res &= __CHECK_CL_ERROR( #_func ); }
#define GL_CALL_BA(  _func, _res )				{ _func;  _res &= __CHECK_API_ERROR( GL,  #_func ); }
#define OS_CALL_BA(  _func, _res )				{ _func;  if ( !__OS_RET_ERROR_VALUE ) _res &= __CHECK_API_ERROR( OS,  #_func ); }


// при возникновении ошибки выходит из функции
// возвращая значение _ret
#define AL_CALL_RV(  _func, _ret )				{ _func;  if ( !__CHECK_API_ERROR( AL,  #_func ) ) return _ret; }
#define ALC_CALL_RV( _func, _ret )				{ _func;  if ( !__CHECK_API_ERROR( ALC, #_func ) ) return _ret; }
#define CL_CALL_RV(  _func, _ret )				{ _func;  if ( !__CHECK_CL_ERROR( #_func ) )	   return _ret; }
#define GL_CALL_RV(  _func, _ret )				{ _func;  if ( !__CHECK_API_ERROR( GL,  #_func ) ) return _ret; }
#define OS_CALL_RV(  _func, _ret )				{ _func;  if ( !__OS_RET_ERROR_VALUE and !__CHECK_API_ERROR( OS,  #_func ) ) return _ret; }


// аналогично предыдущему, но возвращает false
#define AL_CALL_R(  _func )						{ _func;  if ( !__CHECK_API_ERROR( AL,  #_func ) ) return false; }
#define ALC_CALL_R( _func )						{ _func;  if ( !__CHECK_API_ERROR( ALC, #_func ) ) return false; }
#define CL_CALL_R(  _func )						{ _func;  if ( !__CHECK_CL_ERROR( #_func ) )	   return false; }
#define GL_CALL_R(  _func )						{ _func;  if ( !__CHECK_API_ERROR( GL,  #_func ) ) return false; }
#define OS_CALL_R(  _func )						{ _func;  if ( !__OS_RET_ERROR_VALUE and !__CHECK_API_ERROR( OS,  #_func ) ) return false; }


#if not defined( _UXS_USE_OPENGL ) and not defined( _UXS_USE_OPENGLES )
#	undef GL_CALL
#	undef GL_CALL_B
#	undef GL_CALL_BA
#	undef GL_CALL_RV
#	undef GL_CALL_R
#endif

#if not defined( _UXS_USE_OPENCL )
#	undef CL_CALL
#	undef CL_CALL_B
#	undef CL_CALL_BA
#	undef CL_CALL_RV
#	undef CL_CALL_R
#endif

#if not defined( _UXS_USE_OPENAL )
#	undef AL_CALL
#	undef ALC_CALL
#	undef AL_CALL_B
#	undef ALC_CALL_B
#	undef AL_CALL_BA
#	undef ALC_CALL_BA
#	undef AL_CALL_RV
#	undef ALC_CALL_RV
#	undef AL_CALL_R
#	undef ALC_CALL_R
#endif

//-------------------------------------------------------------------


#endif	// _UXS_OS_TYPES_H